<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Loading遮罩组件</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            background-color: #f5f5f5;
            padding: 20px;
        }

        .demo-container {
            max-width: 1200px;
            margin: 0 auto;
        }

        .demo-section {
            background: white;
            border-radius: 8px;
            padding: 20px;
            margin-bottom: 20px;
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
        }

        .demo-section h2 {
            margin-bottom: 15px;
            color: #333;
        }

        .demo-buttons {
            display: flex;
            gap: 10px;
            flex-wrap: wrap;
        }

        .btn {
            padding: 10px 20px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 14px;
            transition: all 0.3s;
        }

        .btn-primary {
            background-color: #1890ff;
            color: white;
        }

        .btn-primary:hover {
            background-color: #40a9ff;
        }

        .btn-danger {
            background-color: #ff4d4f;
            color: white;
        }

        .btn-danger:hover {
            background-color: #ff7875;
        }

        .local-demo {
            position: relative;
            height: 200px;
            background: #fafafa;
            border: 2px dashed #d9d9d9;
            border-radius: 4px;
            display: flex;
            align-items: center;
            justify-content: center;
            margin-top: 15px;
        }

        .local-demo-content {
            text-align: center;
            color: #666;
        }

        /* Loading遮罩样式 */
        .loading-overlay {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.5);
            display: flex;
            align-items: center;
            justify-content: center;
            z-index: 9999;
            opacity: 0;
            visibility: hidden;
            transition: all 0.3s ease;
        }

        .loading-overlay.show {
            opacity: 1;
            visibility: visible;
        }

        .loading-overlay.local {
            position: absolute;
            background-color: rgba(255, 255, 255, 0.8);
        }

        .loading-content {
            background: white;
            padding: 30px;
            border-radius: 8px;
            text-align: center;
            box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
            min-width: 200px;
        }

        .loading-overlay.local .loading-content {
            background: transparent;
            padding: 0;
            border-radius: 0;
            box-shadow: none;
            min-width: auto;
            position: relative;
        }

        .loading-spinner {
            width: 40px;
            height: 40px;
            border: 4px solid #f3f3f3;
            border-top: 4px solid #1890ff;
            border-radius: 50%;
            animation: spin 1s linear infinite;
            margin: 0 auto 15px;
        }

        .loading-overlay.local .loading-spinner {
            border: 4px solid #e6f7ff;
            border-top: 4px solid #1890ff;
        }

        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }

        .loading-text {
            color: #666;
            font-size: 14px;
            margin: 0;
        }

        .loading-overlay.local .loading-text {
            color: #1890ff;
            font-weight: 500;
        }

        /* 点状加载动画 */
        .loading-dots {
            display: inline-block;
        }

        .loading-dots::after {
            content: '';
            animation: dots 1.5s steps(4, end) infinite;
        }

        @keyframes dots {
            0%, 20% { content: ''; }
            40% { content: '.'; }
            60% { content: '..'; }
            80%, 100% { content: '...'; }
        }


    </style>
</head>
<body>
    <div class="demo-container">
        <h1>Loading遮罩组件演示</h1>
        
        <div class="demo-section">
            <h2>全局Loading遮罩</h2>
            <p>覆盖整个页面的loading遮罩，适用于页面级别的加载状态。</p>
            <div class="demo-buttons">
                <button class="btn btn-primary" onclick="showGlobalLoading()">显示全局Loading</button>
                <button class="btn btn-primary" onclick="showGlobalLoading('数据加载中，请稍候...')">显示自定义文本</button>
                <button class="btn btn-danger" onclick="hideGlobalLoading()">隐藏Loading</button>
            </div>
        </div>

        <div class="demo-section">
            <h2>局部Loading遮罩</h2>
            <p>只覆盖指定容器的loading遮罩，适用于组件级别的加载状态。</p>
            <div class="demo-buttons">
                <button class="btn btn-primary" onclick="showLocalLoading()">显示局部Loading</button>
                <button class="btn btn-primary" onclick="showLocalLoading('处理中...')">显示自定义文本</button>
                <button class="btn btn-danger" onclick="hideLocalLoading()">隐藏Loading</button>
            </div>
            <div class="local-demo" id="localDemo">
                <div class="local-demo-content">
                    <h3>局部容器区域</h3>
                    <p>这里是需要显示局部loading的内容区域</p>
                </div>
            </div>
        </div>

        <div class="demo-section">
            <h2>自动隐藏演示</h2>
            <p>可以设置loading自动隐藏的时间。</p>
            <div class="demo-buttons">
                <button class="btn btn-primary" onclick="showAutoHideLoading()">3秒后自动隐藏</button>
                <button class="btn btn-primary" onclick="showLocalAutoHide()">局部2秒后自动隐藏</button>
            </div>
        </div>

        <div class="demo-section">
            <h2>引用计数测试</h2>
            <p>测试多次调用和引用计数功能，查看控制台输出。</p>
            <div class="demo-buttons">
                <button class="btn btn-primary" onclick="testReferenceCount()">测试引用计数</button>
                <button class="btn btn-primary" onclick="console.log('当前状态:', loading.getStatus())">查看当前状态</button>
                <button class="btn btn-danger" onclick="loading.hideAll(true); console.log('强制隐藏后:', loading.getStatus())">强制隐藏所有</button>
            </div>
        </div>

        <div class="demo-section">
            <h2>局部Loading示例（无加载框）</h2>
            <p>演示在指定容器中显示局部loading效果，无额外加载框。</p>
            <div class="demo-buttons">
                <button class="btn btn-primary" onclick="showLocalSimpleLoading()">显示简洁局部Loading</button>
                <button class="btn btn-danger" onclick="hideLocalSimpleLoading()">隐藏简洁局部Loading</button>
            </div>
            <div id="localSimpleDemo" style="width: 100%; height: 200px; border: 1px solid #ddd; margin: 20px 0; position: relative; display: flex; align-items: center; justify-content: center; background: #f9f9f9; border-radius: 4px;">
                <p style="color: #666; text-align: center;">这是一个容器，点击按钮查看局部loading效果（无加载框）</p>
            </div>
            
            <h3>使用代码示例</h3>
            <div style="background: #f5f5f5; padding: 15px; border-radius: 4px; margin: 10px 0; border-left: 4px solid #1890ff;">
                <h4>HTML结构：</h4>
                <pre style="background: #fff; padding: 10px; border-radius: 4px; overflow-x: auto;"><code>&lt;div id="myContainer" style="position: relative; width: 300px; height: 200px;"&gt;
    &lt;!-- 你的内容 --&gt;
    &lt;p&gt;这里是容器内容&lt;/p&gt;
&lt;/div&gt;</code></pre>
                
                <h4>JavaScript调用：</h4>
                <pre style="background: #fff; padding: 10px; border-radius: 4px; overflow-x: auto;"><code>// 显示局部loading（无加载框）
const container = document.getElementById('myContainer');
LoadingMask.showLocal(container, '加载中...');

// 隐藏局部loading
LoadingMask.hideLocal(container);</code></pre>
                
                <h4>完整示例：</h4>
                <pre style="background: #fff; padding: 10px; border-radius: 4px; overflow-x: auto;"><code>// 模拟异步操作
function loadData() {
    const container = document.getElementById('myContainer');
    
    // 显示loading
    LoadingMask.showLocal(container, '数据加载中...');
    
    // 模拟API请求
    setTimeout(() => {
        // 隐藏loading
        LoadingMask.hideLocal(container);
        console.log('数据加载完成');
    }, 2000);
}</code></pre>
            </div>
        </div>
    </div>

    <script>
        /**
         * Loading遮罩组件
         * 支持全局和局部两种模式，支持引用计数管理
         */
        class LoadingMask {
            constructor() {
                this.globalOverlay = null;
                this.localOverlays = new Map();
                this.globalCount = 0; // 全局loading引用计数
                this.localCounts = new Map(); // 局部loading引用计数
            }

            /**
             * 创建loading遮罩元素
             * @param {string} text - 显示文本
             * @param {boolean} isLocal - 是否为局部遮罩
             * @returns {HTMLElement}
             */
            createOverlay(text = '加载中...', isLocal = false) {
                const overlay = document.createElement('div');
                overlay.className = `loading-overlay${isLocal ? ' local' : ''}`;
                
                const content = document.createElement('div');
                content.className = 'loading-content';
                content.style.position = 'relative';
                
                const spinner = document.createElement('div');
                spinner.className = 'loading-spinner';
                
                const textElement = document.createElement('p');
                textElement.className = 'loading-text';
                textElement.innerHTML = `<span class="loading-dots">${text}</span>`;
                
                content.appendChild(spinner);
                content.appendChild(textElement);
                overlay.appendChild(content);
                
                return overlay;
            }

            /**
             * 显示全局loading遮罩
             * @param {string} text - 显示文本
             * @param {number} autoHide - 自动隐藏时间(毫秒)，0表示不自动隐藏
             */
            showGlobal(text = '加载中...', autoHide = 0) {
                this.globalCount++;
                
                if (this.globalOverlay) {
                    // 更新文本内容
                    const textElement = this.globalOverlay.querySelector('.loading-text .loading-dots');
                    if (textElement) {
                        textElement.textContent = text;
                    }
                    return;
                }
                
                this.globalOverlay = this.createOverlay(text, false);
                document.body.appendChild(this.globalOverlay);
                
                // 触发显示动画
                setTimeout(() => {
                    if (this.globalOverlay) {
                        this.globalOverlay.classList.add('show');
                    }
                }, 10);
                
                // 自动隐藏
                if (autoHide > 0) {
                    setTimeout(() => {
                        this.hideGlobal();
                    }, autoHide);
                }
            }

            /**
             * 隐藏全局loading遮罩
             */
            hideGlobal() {
                if (this.globalCount > 0) {
                    this.globalCount--;
                }
                
                // 只有当引用计数为0时才真正隐藏
                if (this.globalCount > 0 || !this.globalOverlay) {
                    return;
                }
                
                this.globalOverlay.classList.remove('show');
                setTimeout(() => {
                    if (this.globalOverlay && this.globalOverlay.parentNode) {
                        this.globalOverlay.parentNode.removeChild(this.globalOverlay);
                    }
                    this.globalOverlay = null;
                    this.globalCount = 0;
                }, 400);
            }

            /**
             * 显示局部loading遮罩
             * @param {string|HTMLElement} target - 目标容器选择器或元素
             * @param {string} text - 显示文本
             * @param {number} autoHide - 自动隐藏时间(毫秒)，0表示不自动隐藏
             */
            showLocal(target, text = '加载中...', autoHide = 0) {
                const container = typeof target === 'string' ? document.querySelector(target) : target;
                if (!container) {
                    console.error('Loading target container not found:', target);
                    return;
                }

                // 增加引用计数
                const currentCount = this.localCounts.get(container) || 0;
                this.localCounts.set(container, currentCount + 1);
                
                // 如果目标元素已有loading，更新文本并返回
                if (this.localOverlays.has(container)) {
                    const loadingData = this.localOverlays.get(container);
                    const textElement = loadingData.overlay.querySelector('.loading-text .loading-dots');
                    if (textElement) {
                        textElement.textContent = text;
                    }
                    return;
                }
                
                // 确保容器有相对定位
                const originalPosition = container.style.position;
                if (!originalPosition || originalPosition === 'static') {
                    container.style.position = 'relative';
                }
                
                const overlay = this.createOverlay(text, true);
                container.appendChild(overlay);
                this.localOverlays.set(container, { overlay, originalPosition });
                
                // 触发显示动画
                setTimeout(() => {
                    overlay.classList.add('show');
                }, 10);
                
                // 自动隐藏
                if (autoHide > 0) {
                    setTimeout(() => {
                        this.hideLocal(target);
                    }, autoHide);
                }
            }

            /**
             * 隐藏局部loading遮罩
             * @param {string|HTMLElement} target - 目标容器选择器或元素
             */
            hideLocal(target) {
                const container = typeof target === 'string' ? document.querySelector(target) : target;
                if (!container) return;
                
                // 减少引用计数
                const currentCount = this.localCounts.get(container) || 0;
                if (currentCount > 0) {
                    this.localCounts.set(container, currentCount - 1);
                }
                
                // 只有当引用计数为0时才真正隐藏
                if (this.localCounts.get(container) > 0 || !this.localOverlays.has(container)) {
                    return;
                }
                
                const loadingData = this.localOverlays.get(container);
                const { overlay, originalPosition } = loadingData;
                overlay.classList.remove('show');
                
                setTimeout(() => {
                    if (overlay && overlay.parentNode) {
                        overlay.parentNode.removeChild(overlay);
                    }
                    // 恢复原始定位
                    if (originalPosition) {
                        container.style.position = originalPosition;
                    } else {
                        container.style.position = '';
                    }
                    this.localOverlays.delete(container);
                    this.localCounts.delete(container);
                }, 400);
            }

            /**
             * 强制隐藏所有loading遮罩（忽略引用计数）
             * @param {boolean} force - 是否强制隐藏
             */
            hideAll(force = false) {
                if (force) {
                    this.globalCount = 0;
                    this.localCounts.clear();
                }
                
                this.hideGlobal();
                const containers = Array.from(this.localOverlays.keys());
                containers.forEach(container => {
                    if (force) {
                        this.localCounts.set(container, 0);
                    }
                    this.hideLocal(container);
                });
            }

            /**
             * 获取当前loading状态
             */
            getStatus() {
                return {
                    global: !!this.globalOverlay,
                    globalCount: this.globalCount,
                    local: this.localOverlays.size,
                    localCounts: Object.fromEntries(this.localCounts),
                    total: (this.globalOverlay ? 1 : 0) + this.localOverlays.size
                };
            }
        }

        // 创建全局实例
        const loading = new LoadingMask();

        // 全局方法，方便直接调用
        function showGlobalLoading(text, autoHide) {
            loading.showGlobal(text, autoHide);
        }

        function hideGlobalLoading() {
            loading.hideGlobal();
        }

        function showLocalLoading(text, autoHide) {
            loading.showLocal('#localDemo', text, autoHide);
        }

        function hideLocalLoading() {
            loading.hideLocal('#localDemo');
        }

        function showAutoHideLoading() {
            loading.showGlobal('3秒后自动隐藏...', 3000);
        }

        function showLocalAutoHide() {
            loading.showLocal('#localDemo', '2秒后自动隐藏...', 2000);
        }

        // 键盘快捷键支持
        document.addEventListener('keydown', function(e) {
            if (e.key === 'Escape') {
                loading.hideAll(true); // 强制隐藏所有loading
                console.log('ESC强制隐藏后状态:', loading.getStatus());
            }
        });

        // 测试引用计数功能
        function testReferenceCount() {
            console.log('=== 引用计数测试 ===');
            console.log('初始状态:', loading.getStatus());
            
            // 多次调用全局loading
            loading.showGlobal('第1次调用');
            console.log('第1次调用后:', loading.getStatus());
            
            loading.showGlobal('第2次调用');
            console.log('第2次调用后:', loading.getStatus());
            
            loading.showGlobal('第3次调用');
            console.log('第3次调用后:', loading.getStatus());
            
            // 逐步隐藏
            setTimeout(() => {
                loading.hideGlobal();
                console.log('第1次隐藏后:', loading.getStatus());
            }, 1000);
            
            setTimeout(() => {
                loading.hideGlobal();
                console.log('第2次隐藏后:', loading.getStatus());
            }, 2000);
            
            setTimeout(() => {
                loading.hideGlobal();
                console.log('第3次隐藏后:', loading.getStatus());
            }, 3000);
        }
        

        
        // 暴露测试函数到全局
        window.testReferenceCount = testReferenceCount;

        // 局部loading使用示例（无加载框）
         window.showLocalSimpleLoading = function() {
             const container = document.getElementById('localSimpleDemo');
             LoadingMask.showLocal(container, '数据加载中...');
         }
 
         window.hideLocalSimpleLoading = function() {
             const container = document.getElementById('localSimpleDemo');
             LoadingMask.hideLocal(container);
         }



        // 使用示例和API说明
        console.log(`
=== Loading遮罩组件使用说明 ===

1. 全局Loading:
   loading.showGlobal('加载中...', 3000); // 显示3秒后自动隐藏
   loading.hideGlobal(); // 手动隐藏

2. 局部Loading:
   loading.showLocal('#container', '处理中...', 2000); // 在指定容器显示
   loading.hideLocal('#container'); // 隐藏指定容器的loading

3. 快捷方法:
   showGlobalLoading('文本', 自动隐藏时间);
   hideGlobalLoading();
   showLocalLoading('文本', 自动隐藏时间);
   hideLocalLoading();

4. 快捷键:
   按ESC键可隐藏所有loading遮罩

5. 特性:
   - 支持自定义文本
   - 支持自动隐藏
   - 平滑的显示/隐藏动画
   - 响应式设计
   - 可同时显示多个局部loading
   - 自动处理容器定位
        `);
    </script>
</body>
</html>